package com.aat.modle.renzhengheyi.kalala;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.security.InvalidKeyException;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.SecureRandom;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;

import javax.crypto.BadPaddingException;
import javax.crypto.Cipher;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;


public class RSAUtils {
	

	/**
	 * 字节数据转字符串专用集合
	 */
	private static final char[] HEX_CHAR = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e',
			'f' };

	/**
	 * 随机生成密钥对
	 */
	public static KeyPair newKeyPair() {
		KeyPairGenerator keyPairGen = null;
		try {
			keyPairGen = KeyPairGenerator.getInstance("RSA");
		} catch (NoSuchAlgorithmException e) {
			e.printStackTrace();
		}
		keyPairGen.initialize(1024, new SecureRandom("123456".getBytes()));//种子123456
		KeyPair keyPair = keyPairGen.generateKeyPair();
		return keyPair;
	}

	/**
	 * 从文件中获取公钥
	 * 
	 * @author panchangwei
	 * @data 2016年4月27日 下午2:34:06
	 * @param in
	 * @return 当前公钥对象
	 * @throws Exception
	 */
	public static RSAPublicKey getPublicKey(InputStream in) throws Exception {
		try {
			BufferedReader br = new BufferedReader(new InputStreamReader(in));
			String readLine = null;
			StringBuilder sb = new StringBuilder();
			while ((readLine = br.readLine()) != null) {
				if (readLine.charAt(0) == '-') {
					continue;
				} else {
					sb.append(readLine);
					sb.append('\r');
				}
			}
			return getPublicKey(sb.toString());
		} catch (IOException e) {
			throw new Exception("公钥数据流读取错误");
		} catch (NullPointerException e) {
			throw new Exception("公钥输入流为空");
		}
	}

	/**
	 * 从字符串中获得公钥
	 * 
	 * @data 2016年4月27日 下午2:35:07
	 * @param publicKeyStr
	 *            加密字符串
	 * @return 当前公钥对象s
	 * @throws Exception
	 */
	public static RSAPublicKey getPublicKey(String publicKeyStr) throws Exception {
		try {
			byte[] buffer = Base64.decode(publicKeyStr);
			KeyFactory keyFactory = KeyFactory.getInstance("RSA");
			X509EncodedKeySpec keySpec = new X509EncodedKeySpec(buffer);
			return (RSAPublicKey) keyFactory.generatePublic(keySpec);
		} catch (NoSuchAlgorithmException e) {
			throw new Exception("无此算法");
		} catch (InvalidKeySpecException e) {
			throw new Exception("公钥非法");
		} catch (NullPointerException e) {
			throw new Exception("公钥数据为空");
		}
	}

	/**
	 * 从文件中获取私钥
	 * 
	 * @data 2016年4月27日 下午2:32:19
	 * @param in
	 * @return 私钥对象
	 * @throws Exception
	 */
	public static RSAPrivateKey getPrivateKey(InputStream in) throws Exception {
		try {
			BufferedReader br = new BufferedReader(new InputStreamReader(in));
			String readLine = null;
			StringBuilder sb = new StringBuilder();
			while ((readLine = br.readLine()) != null) {
				if (readLine.charAt(0) == '-') {
					continue;
				} else {
					sb.append(readLine);
					sb.append('\r');
				}
			}
			return getPrivateKey(sb.toString());
		} catch (IOException e) {
			throw new Exception("私钥数据读取错误");
		} catch (NullPointerException e) {
			throw new Exception("私钥输入流为空");
		}
	}

	/**
	 * 从字符串中获取私钥
	 * 
	 * @data 2016年4月27日 下午2:33:14
	 * @param privateKeyStr
	 * @return
	 * @throws Exception
	 */
	public static RSAPrivateKey getPrivateKey(String privateKeyStr) throws Exception {
		try {
			byte[] buffer = Base64.decode(privateKeyStr);
			PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(buffer);
			KeyFactory keyFactory = KeyFactory.getInstance("RSA");
			return (RSAPrivateKey) keyFactory.generatePrivate(keySpec);
		} catch (NoSuchAlgorithmException e) {
			throw new Exception("无此算法");
		} catch (InvalidKeySpecException e) {
			throw new Exception("私钥非法");
		} catch (NullPointerException e) {
			throw new Exception("私钥数据为空");
		}
	}

	public static String encryptString(RSAPublicKey publicKey, String plainStr) {
		try {
			return new String(encrypt(publicKey, plainStr.getBytes()));
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return "";
	}

	/**
	 * 加密
	 * 
	 * @param publicKey
	 *            公钥
	 * @param plainTextData
	 *            明文数据
	 * @return
	 * @throws Exception
	 *             加密过程中的异常信息
	 */
	public static byte[] encrypt(RSAPublicKey publicKey, byte[] plainTextData) throws Exception {
		if (publicKey == null) {
			throw new Exception("加密公钥为空, 请设置");
		}
		Cipher cipher = null;
		try {
			cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
			cipher.init(Cipher.ENCRYPT_MODE, publicKey);
			byte[] output = cipher.doFinal(plainTextData);
			return output;
		} catch (NoSuchAlgorithmException e) {
			throw new Exception("无此加密算法");
		} catch (NoSuchPaddingException e) {
			e.printStackTrace();
			return null;
		} catch (InvalidKeyException e) {
			throw new Exception("加密公钥非法,请检查");
		} catch (IllegalBlockSizeException e) {
			throw new Exception("明文长度非法");
		} catch (BadPaddingException e) {
			throw new Exception("明文数据已损坏");
		}
	}

	/**
	 * 解密过程
	 * 
	 * @param privateKey
	 *            私钥
	 * @param cipherData
	 *            密文数据
	 * @return 明文
	 * @throws Exception
	 *             解密过程中的异常信息
	 */
	public static byte[] decrypt(RSAPrivateKey privateKey, byte[] cipherData) throws Exception {
		if (privateKey == null) {
			throw new Exception("解密私钥为空, 请设置");
		}
		Cipher cipher = null;
		try {
			cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
			cipher.init(Cipher.DECRYPT_MODE, privateKey);
			byte[] output = cipher.doFinal(cipherData);
			return output;
		} catch (NoSuchAlgorithmException e) {
			throw new Exception("无此解密算法");
		} catch (NoSuchPaddingException e) {
			e.printStackTrace();
			return null;
		} catch (InvalidKeyException e) {
			throw new Exception("解密私钥非法,请检查");
		} catch (IllegalBlockSizeException e) {
			throw new Exception("密文长度非法");
		} catch (BadPaddingException e) {
			throw new Exception("密文数据已损坏");
		}
	}

	/**
	 * 字节数据转十六进制字符串
	 * 
	 * @param data
	 *            输入数据
	 * @return 十六进制内容
	 */
	public static String byteArrayToString(byte[] data) {
		StringBuilder stringBuilder = new StringBuilder();
		for (int i = 0; i < data.length; i++) {
			// 取出字节的高四位 作为索引得到相应的十六进制标识符 注意无符号右移
			stringBuilder.append(HEX_CHAR[(data[i] & 0xf0) >>> 4]);
			// 取出字节的低四位 作为索引得到相应的十六进制标识符
			stringBuilder.append(HEX_CHAR[(data[i] & 0x0f)]);
			if (i < data.length - 1) {
				stringBuilder.append(' ');
			}
		}
		return stringBuilder.toString();
	}

	
	
    public static final String SIGN_ALGORITHMS = "SHA1WithRSA";
    
    /**
    * RSA签名
    * @param content 待签名数据
    * @param privateKey 商户私钥
    * @param input_charset 编码格式
    * @return 签名值
    */
    public static String sign(String content, String privateKey, String input_charset)
    {
        try
        {
            PKCS8EncodedKeySpec priPKCS8    = new PKCS8EncodedKeySpec(Base64.decode(privateKey));
            KeyFactory keyf                 = KeyFactory.getInstance("RSA");
            PrivateKey priKey               = keyf.generatePrivate(priPKCS8);
            java.security.Signature signature = java.security.Signature
                .getInstance(SIGN_ALGORITHMS);
            signature.initSign(priKey);
            signature.update( content.getBytes(input_charset) );
            byte[] signed = signature.sign();
            return Base64.encode(signed);
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
         
        return null;
    }
    
    
    /**
     * RSA验签名检查
     * @param content 待签名数据
     * @param sign 签名值
     * @param input_charset 编码格式
     * @return 布尔值
     */
     public static boolean verify(String content, String sign, String publicKey, String input_charset)
     {
         try
         {
             KeyFactory keyFactory = KeyFactory.getInstance("RSA");
             byte[] encodedKey = Base64.decode(publicKey);
             PublicKey pubKey = keyFactory.generatePublic(new X509EncodedKeySpec(encodedKey));
             java.security.Signature signature = java.security.Signature
             .getInstance(SIGN_ALGORITHMS);
             signature.initVerify(pubKey);
             signature.update( content.getBytes(input_charset) );
             boolean bverify = signature.verify( Base64.decode(sign) );
             return bverify;
              
         }
         catch (Exception e)
         {
             e.printStackTrace();
         }
          
         return false;
     }
     
     
     
 	/**
 	 * 私钥
 	 * 
 	 * @param plainTextData
 	 *            明文数据
 	 * @return
 	 * @throws Exception
 	 *             加密过程中的异常信息
 	 */
 	public static byte[] encrypt(RSAPrivateKey privateKey, byte[] plainTextData) throws Exception {
 		if (privateKey == null) {
 			throw new Exception("加密私钥为空, 请设置");
 		}
 		Cipher cipher = null;
 		try {
 			cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
 			cipher.init(Cipher.ENCRYPT_MODE, privateKey);
 			byte[] output = cipher.doFinal(plainTextData);
 			return output;
 		} catch (NoSuchAlgorithmException e) {
 			throw new Exception("无此加密算法");
 		} catch (NoSuchPaddingException e) {
 			e.printStackTrace();
 			return null;
 		} catch (InvalidKeyException e) {
 			throw new Exception("加密私钥非法,请检查");
 		} catch (IllegalBlockSizeException e) {
 			throw new Exception("明文长度非法");
 		} catch (BadPaddingException e) {
 			throw new Exception("明文数据已损坏");
 		}
 	}
     
 	
 	/**
 	 * 私钥加密
 	 * @param privateKey
 	 * @param plainStr
 	 * @return
 	 */
	public static String encryptString(RSAPrivateKey privateKey, String plainStr) {
		try {
			return Base64.encode(encrypt(privateKey, plainStr.getBytes()));
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return "";
	}

	/**
 	 * gongyao加密
 	 * @param publicKey
 	 * @param plainStr
 	 * @return
 	 */
	public static String encryptString(String publicKey, String plainStr) {
		try {
			return Base64.encode(encrypt(getPublicKey(publicKey), plainStr.getBytes()));
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		return "";
	}
 	
 	
	/**
	 * 解密过程
	 * 
	 *            私钥
	 * @param cipherData
	 *            密文数据
	 * @return 明文
	 * @throws Exception
	 *             解密过程中的异常信息
	 */
	public static byte[] decrypt(RSAPublicKey rsaPublicKey, byte[] cipherData) throws Exception {
		if (rsaPublicKey == null) {
			throw new Exception("公钥密私钥为空, 请设置");
		}
		Cipher cipher = null;
		try {
			cipher = Cipher.getInstance("RSA/ECB/PKCS1Padding");
			cipher.init(Cipher.DECRYPT_MODE, rsaPublicKey);
			byte[] output = cipher.doFinal(cipherData);
			return output;
		} catch (NoSuchAlgorithmException e) {
			throw new Exception("无此解密算法");
		} catch (NoSuchPaddingException e) {
			e.printStackTrace();
			return null;
		} catch (InvalidKeyException e) {
			throw new Exception("解密私钥非法,请检查");
		} catch (IllegalBlockSizeException e) {
			throw new Exception("密文长度非法");
		} catch (BadPaddingException e) {
			throw new Exception("密文数据已损坏");
		}
	}
	
	
	
	public static byte[] decryptString(RSAPublicKey rsaPublicKey, String data) throws Exception {
		return decrypt(rsaPublicKey, Base64.decode(data));
	}
	
	



    public static void main(String[] args) throws Exception {

    	KeyPair keyPair = newKeyPair();
    	String prikey = Base64.encode(keyPair.getPrivate().getEncoded());
    	String pubKey =  Base64.encode(keyPair.getPublic().getEncoded());
    	System.out.println(pubKey);
    	System.out.println(prikey);
    	String str =encryptString((RSAPrivateKey)keyPair.getPrivate(), "123123");
    	System.out.println(str);
    	System.out.println(new String(decryptString((RSAPublicKey)keyPair.getPublic(), str)));



  		String sign = sign("123123", prikey, "UTF-8");
    	System.out.println(sign);
    	System.out.println(verify("1231236", sign, pubKey, "UTF-8"));


	}
}
